package org.jwos.platform.ajax;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;

import org.springframework.context.ApplicationContext;

public class JSONProxy {
	
	private ApplicationContext context = null;
	
	private ClassLoader classLoader = null;
	
	public JSONProxy() {		
	}
	
	public JSONProxy(ApplicationContext context,ClassLoader classLoader) {
		this.setContext(context);
		this.setClassLoader(classLoader);
	}

	public String call(String data) {

		JSONRequest req = null;
		JSONResponse res = new JSONResponse();
		boolean directReturn = false;
		String resData = "";
		try {
			// transform json string to Java object
			req = (JSONRequest) JSONCoder.decode(data);
			directReturn = req.getDirectReturn();

			// call service method
			Object result = invoke(req);
			resData = String.valueOf(result);			

			// process result
			res.setSuccess(true);
			res.setResult(result);
		} catch (Throwable t) {
			t.printStackTrace();

			// process exception
			res.setSuccess(false);
			if (t instanceof InvocationTargetException) {
				t = ((InvocationTargetException) t).getTargetException();
			}
			res.setError(t.getMessage());
		} finally {
			try {
				// encode and send response data
				if (!directReturn) {
					resData = JSONCoder.encode(res);
				}
			} catch (Throwable t) {
				t.printStackTrace();
			}
		}
		
		return resData;
	}
	
	protected Object invoke(JSONRequest req) throws Exception {

		if (req.getService() == null || req.getService().length() == 0)
			throw new Exception("Service is null");
		if (req.getType() == null || req.getType().length() == 0)
			throw new Exception("Type is null");
		if (req.getMethod() == null || req.getMethod().length() == 0)
			throw new Exception("Method is null");

		Object service = null;
		Method method = null;
		try {
			service = getServiceById(req.getService());
		} catch (Exception ex) {
			throw new Exception("Cannot found the service:" + req.getService());
		}

		try {
			method = getMethodByName(req.getType(), req.getMethod());
		} catch (Exception ex) {
			throw new Exception("Cannot found the method of service(" + req.getService() + "):" + req.getMethod());
		}

		if (method.getParameterTypes() != null
				&& method.getParameterTypes().length > 0) {
			return method.invoke(service, new Object[] { req.getParameter() });
		} else {
			return method.invoke(service, new Object[] {});
		}
	}
	
	protected Object getServiceById(String serviceId) {
		System.out.println(this.getContext().getType(serviceId));
		return this.getContext().getBean(serviceId);
	}
	
	protected Method getMethodByName(String serviceType, String methodName) throws Exception {		
		Method[] methods = this.classLoader.loadClass(serviceType).getMethods();
		for (int i = 0; methods != null && i < methods.length; i++) {
			if (methods[i].getName().equalsIgnoreCase(methodName))
				return methods[i];
		}
		throw new NoSuchMethodException(serviceType + "." + methodName);
	}	

	public static String getDataString(HttpServletRequest request) throws Exception {

		byte[] buf = new byte[request.getContentLength()];
		byte[] ch = new byte[1];
		int count = 0;
		while (count < buf.length) {
			if (request.getInputStream().read(ch) > 0) {
				buf[count] = ch[0];
				count++;
			}
		}

		return new String(new String(buf, "ISO-8859-1").getBytes("ISO-8859-1"),"UTF-8");
	}

	public ApplicationContext getContext() {
		return context;
	}

	public void setContext(ApplicationContext context) {
		this.context = context;
	}

	public ClassLoader getClassLoader() {
		return classLoader;
	}

	public void setClassLoader(ClassLoader classLoader) {
		this.classLoader = classLoader;
	}
}
